/**
 * 文件上传相关配置
 * 与后端 application.yml 中的配置保持一致
 */

// 文件大小限制 (字节)
export const FILE_SIZE_LIMITS = {
  // 单个文件最大大小 (1GB) - 与后端 spring.servlet.multipart.max-file-size 一致
  MAX_FILE_SIZE: 1024 * 1024 * 1024, // 1GB
  
  // 整个请求最大大小 (1GB) - 与后端 spring.servlet.multipart.max-request-size 一致
  MAX_REQUEST_SIZE: 1024 * 1024 * 1024, // 1GB
  
  // 分片大小 (2MB) - 分片上传时每个分片的大小
  CHUNK_SIZE: 2 * 1024 * 1024, // 2MB
  
  // 警告阈值 (100MB) - 超过此大小会提示用户使用分片上传
  WARNING_SIZE: 100 * 1024 * 1024 // 100MB
}

// 文件类型限制
export const FILE_TYPE_LIMITS = {
  // 允许的文件类型 (空数组表示允许所有类型)
  ALLOWED_TYPES: [] as string[],
  
  // 禁止的文件类型
  FORBIDDEN_TYPES: [
    '.exe', '.bat', '.cmd', '.com', '.scr', '.pif',
    '.vbs', '.js', '.jar', '.app', '.deb', '.rpm'
  ],
  
  // 图片类型
  IMAGE_TYPES: [
    'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 
    'image/bmp', 'image/webp', 'image/svg+xml'
  ],
  
  // 视频类型
  VIDEO_TYPES: [
    'video/mp4', 'video/avi', 'video/mov', 'video/wmv',
    'video/flv', 'video/webm', 'video/mkv'
  ],
  
  // 音频类型
  AUDIO_TYPES: [
    'audio/mp3', 'audio/wav', 'audio/flac', 'audio/aac',
    'audio/ogg', 'audio/wma'
  ],
  
  // 文档类型
  DOCUMENT_TYPES: [
    'application/pdf',
    'application/msword',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'application/vnd.ms-excel',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'application/vnd.ms-powerpoint',
    'application/vnd.openxmlformats-officedocument.presentationml.presentation',
    'text/plain', 'text/csv'
  ]
}

// 上传配置
export const UPLOAD_CONFIG = {
  // 最大并发分片数
  MAX_CONCURRENT_CHUNKS: 3,
  
  // 最大并发文件数
  MAX_CONCURRENT_FILES: 2,
  
  // 重试次数
  MAX_RETRY_COUNT: 3,
  
  // 超时时间 (毫秒)
  TIMEOUT: 5 * 60 * 1000, // 5分钟
  
  // 是否启用断点续传
  ENABLE_RESUME: true,
  
  // 是否启用文件去重 (SHA256检查)
  ENABLE_DEDUPLICATION: true
}

/**
 * 格式化文件大小
 * @param bytes 字节数
 * @returns 格式化后的文件大小字符串
 */
export function formatFileSize(bytes: number): string {
  if (bytes === 0) return '0 B'
  
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

/**
 * 验证文件大小
 * @param file 文件对象
 * @returns 验证结果
 */
export function validateFileSize(file: File): {
  valid: boolean
  message?: string
  isLarge?: boolean
} {
  if (file.size > FILE_SIZE_LIMITS.MAX_FILE_SIZE) {
    return {
      valid: false,
      message: `文件 ${file.name} 大小 ${formatFileSize(file.size)} 超过最大限制 ${formatFileSize(FILE_SIZE_LIMITS.MAX_FILE_SIZE)}`
    }
  }
  
  if (file.size > FILE_SIZE_LIMITS.WARNING_SIZE) {
    return {
      valid: true,
      isLarge: true,
      message: `文件 ${file.name} 较大 (${formatFileSize(file.size)})，将使用分片上传`
    }
  }
  
  return { valid: true }
}

/**
 * 验证文件类型
 * @param file 文件对象
 * @returns 验证结果
 */
export function validateFileType(file: File): {
  valid: boolean
  message?: string
} {
  // 检查禁止的文件扩展名
  const fileName = file.name.toLowerCase()
  const hasForbiddenExtension = FILE_TYPE_LIMITS.FORBIDDEN_TYPES.some(ext => 
    fileName.endsWith(ext.toLowerCase())
  )
  
  if (hasForbiddenExtension) {
    return {
      valid: false,
      message: `文件类型 ${fileName.split('.').pop()} 不被允许上传`
    }
  }
  
  // 如果设置了允许的类型，检查是否在允许列表中
  if (FILE_TYPE_LIMITS.ALLOWED_TYPES.length > 0) {
    const isAllowed = FILE_TYPE_LIMITS.ALLOWED_TYPES.some(type => 
      file.type.startsWith(type) || fileName.endsWith(type)
    )
    
    if (!isAllowed) {
      return {
        valid: false,
        message: `文件类型 ${file.type || '未知'} 不在允许的类型列表中`
      }
    }
  }
  
  return { valid: true }
}

/**
 * 获取文件类型分类
 * @param file 文件对象
 * @returns 文件类型分类
 */
export function getFileCategory(file: File): 'image' | 'video' | 'audio' | 'document' | 'other' {
  const { type } = file
  
  if (FILE_TYPE_LIMITS.IMAGE_TYPES.includes(type)) return 'image'
  if (FILE_TYPE_LIMITS.VIDEO_TYPES.includes(type)) return 'video'
  if (FILE_TYPE_LIMITS.AUDIO_TYPES.includes(type)) return 'audio'
  if (FILE_TYPE_LIMITS.DOCUMENT_TYPES.includes(type)) return 'document'
  
  return 'other'
}
